﻿using In66.Net.EventBus.RabbitMq.Attributes;
using In66.Net.EventBus.RabbitMq.IIntegration;
using Microsoft.Extensions.DependencyModel;
using System.ComponentModel;
using System.Reflection;

namespace In66.Net.EventBus
{
    public static class EventBusExtensions
    {
        private static readonly string[] Filters = { "dotnet-", "Microsoft.", "mscorlib", "netstandard", "System", "Windows" };
        private static readonly IEnumerable<Assembly>? _allAssemblies;
        private static readonly IEnumerable<Type>? _allTypes;

        /// <summary>
        /// 需要排除的项目
        /// </summary>
        private static readonly List<string> FilterLibs = new();

        /// <summary>
        /// 构造函数
        /// </summary>
        static EventBusExtensions()
        {
            _allAssemblies = DependencyContext.Default?.GetDefaultAssemblyNames().Where(c => c.Name is not null && !Filters.Any(c.Name.StartsWith) && !FilterLibs.Any(c.Name.StartsWith)).Select(Assembly.Load);
            _allTypes = _allAssemblies?.SelectMany(c => c.GetTypes());
        }

        #region tools

        /// <summary>
        /// 查找指定条件的类型
        /// </summary>
        public static IEnumerable<Type> FindTypes(Func<Type, bool> predicate) => _allTypes!.Where(predicate).ToArray();

        /// <summary>
        /// 返回当前类型是否是指定基类的派生类
        /// </summary>
        /// <param name="type">当前类型</param>
        /// <param name="baseType">要判断的基类型</param>
        /// <returns></returns>
        public static bool IsBaseOn(this Type type, Type baseType) => baseType.IsGenericTypeDefinition ? type.HasImplementedRawGeneric(baseType) : baseType.IsAssignableFrom(type);

        /// <summary>
        /// 判断指定的类型 <paramref name="type" /> 是否是指定泛型类型的子类型，或实现了指定泛型接口。
        /// </summary>
        /// <param name="type">需要测试的类型。</param>
        /// <param name="generic">泛型接口类型，传入 typeof(IXxx&lt;&gt;)</param>
        /// <returns>如果是泛型接口的子类型，则返回 true，否则返回 false。</returns>
        public static bool HasImplementedRawGeneric(this Type type, Type generic)
        {
            type.NotNull(nameof(type));
            generic.NotNull(nameof(generic));
            // 测试接口。
            var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
            if (isTheRawGenericType)
            {
                return true;
            }
            // 测试类型。
            while (type != typeof(object))
            {
                isTheRawGenericType = IsTheRawGenericType(type);
                if (isTheRawGenericType)
                {
                    return true;
                }

                type = type.BaseType!;
            }
            // 没有找到任何匹配的接口或类型。
            return false;

            // 测试某个类型是否是指定的原始接口。
            bool IsTheRawGenericType(Type test) => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
        }

        /// <summary>
        /// 检查参数不能为空引用，否则抛出<see cref="ArgumentNullException" />异常。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="paramName">参数名称</param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void NotNull<T>(this T value, string paramName) => Require<ArgumentNullException>(value is not null, $"参数“{paramName}”不能为空引用。");

        /// <summary>
        /// 验证指定值的断言<paramref name="assertion" />是否为真，如果不为真，抛出指定消息<paramref name="message" />的指定类型<typeparamref name="TException" />异常
        /// </summary>
        /// <typeparam name="TException">异常类型</typeparam>
        /// <param name="assertion">要验证的断言。</param>
        /// <param name="message">异常消息。</param>
        public static void Require<TException>(bool assertion, string message) where TException : Exception
        {
            if (assertion)
            {
                return;
            }
#if NET7_0_OR_GREATER
        ArgumentException.ThrowIfNullOrEmpty(message, nameof(message));
#else
            if (string.IsNullOrWhiteSpace(message))
            {
                throw new ArgumentNullException(nameof(message));
            }
#endif
            throw (TException)Activator.CreateInstance(typeof(TException), message)!;
        }

        /// <summary>
        /// 转成显示名字
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static string? ToDescription(this Enum value)
        {
            var member = value.GetType().GetMember(value.ToString()).FirstOrDefault();
            return member?.ToDescription();
        }

        /// <summary>
        /// 获取描述或者显示名称
        /// </summary>
        /// <param name="member"></param>
        /// <returns></returns>
        internal static string ToDescription(this MemberInfo member)
        {
            var desc = member.GetCustomAttribute<DescriptionAttribute>();
            if (desc is not null)
            {
                return desc.Description;
            }
            //显示名
            var display = member.GetCustomAttribute<DisplayNameAttribute>();
            return display is not null ? display.DisplayName : member.Name;
        }

        /// <summary>
        /// 判断特性相应是否存在
        /// </summary>
        /// <typeparam name="T">动态类型要判断的特性</typeparam>
        /// <param name="memberInfo"></param>
        /// <param name="inherit"></param>
        /// <returns>如果存在还在返回true，否则返回false</returns>
        public static bool HasAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute => memberInfo.IsDefined(typeof(T), inherit);

        /// <summary>
        /// 具有相匹配的通用类型
        /// </summary>
        /// <param name="interfaceType">接口类型</param>
        /// <param name="typeInfo">对象类型</param>
        /// <returns></returns>
        public static bool HasMatchingGenericArity(this Type interfaceType, TypeInfo typeInfo)
        {
            if (!typeInfo.IsGenericType)
            {
                return true;
            }

            var interfaceTypeInfo = interfaceType.GetTypeInfo();
            if (!interfaceTypeInfo.IsGenericType)
            {
                return false;
            }

            var argumentCount = interfaceType.GenericTypeArguments.Length;
            var parameterCount = typeInfo.GenericTypeParameters.Length;
            return argumentCount == parameterCount;
        }

        #endregion

        /// <summary>
        /// 获取Header的属性
        /// </summary>
        /// <param name="event"></param>
        /// <returns></returns>
        internal static IDictionary<string, object>? GetHeaderAttributes(this IIntegrationEvent @event)
        {
            var type = @event.GetType();
            var rabbitHeaderAttributes = type.GetCustomAttributes<RabbitHeaderAttribute>();
            return RabbitDictionariesByDic(rabbitHeaderAttributes);
        }

        /// <summary>
        /// 获取交换机的Arguments
        /// </summary>
        /// <param name="event"></param>
        /// <returns></returns>
        internal static IDictionary<string, object>? GetExchangeArgAttributes(this IIntegrationEvent @event)
        {
            var type = @event.GetType();
            var exchangeArgs = type.GetCustomAttributes<RabbitExchangeArgAttribute>();
            return RabbitDictionariesByDic(exchangeArgs);
        }

        /// <summary>
        /// 获取交换机的Arguments
        /// </summary>
        /// <param name="eventType"></param>
        /// <returns></returns>
        internal static IDictionary<string, object>? GetExchangeArgAttributes(this Type eventType)
        {
            var exchangeArgs = eventType.GetCustomAttributes<RabbitExchangeArgAttribute>();
            return RabbitDictionariesByDic(exchangeArgs);
        }

        /// <summary>
        /// 获取交换机的Arguments
        /// </summary>
        /// <param name="event"></param>
        /// <returns></returns>
        internal static IDictionary<string, object>? GetQueueArgAttributes(this IIntegrationEvent @event)
        {
            var type = @event.GetType();
            var queueArgs = type.GetCustomAttributes<RabbitQueueArgAttribute>();
            return RabbitDictionariesByDic(queueArgs);
        }

        /// <summary>
        /// 获取交换机的Arguments
        /// </summary>
        /// <param name="eventType"></param>
        /// <returns></returns>
        internal static IDictionary<string, object>? GetQueueArgAttributes(this Type eventType)
        {
            var queueArgs = eventType.GetCustomAttributes<RabbitQueueArgAttribute>();
            return RabbitDictionariesByDic(queueArgs);
        }

        /// <summary>
        /// 将特性内容转换成字典
        /// </summary>
        /// <param name="rabbitDictionaryAttributes"></param>
        /// <returns></returns>
        private static Dictionary<string, object>? RabbitDictionariesByDic(this IEnumerable<RabbitDictionaryAttribute>? rabbitDictionaryAttributes)
        {
            return rabbitDictionaryAttributes?.ToDictionary(rabbitDictionaryAttribute => rabbitDictionaryAttribute.Key,
                rabbitDictionaryAttribute => rabbitDictionaryAttribute.Value);
        }



        public static string GetGenericTypeName(this Type type)
        {
            var typeName = string.Empty;

            if (type.IsGenericType)
            {
                var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray());
                typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>";
            }
            else
            {
                typeName = type.Name;
            }

            return typeName;
        }

        public static string GetGenericTypeName(this object @object)
        {
            return @object.GetType().GetGenericTypeName();
        }




    }
}
